package com.seeyon.apps.kkARPEvent.util;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.*;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.zip.GZIPInputStream;

/**
 * @description Http请求 辅助类
 */
public class HttpCfgHelper {
	private static Log LOGGER = LogFactory.getLog(HttpCfgHelper.class);
	private static final int MAX_TIMEOUT = 3000; //超时时间
    private static final int MAX_TOTAL=10; //最大连接数
    private static final int ROUTE_MAX_TOTAL=3; //每个路由基础的连接数
    private static final  int MAX_RETRY = 5; //重试次数
	private static PoolingHttpClientConnectionManager connMgr; //连接池
	private static HttpRequestRetryHandler retryHandler; //重试机制
    
    static {
    	cfgPoolMgr();
    	cfgRetryHandler();
    }
      

	/**
     * @description 发起HTTP / HTTPS 请求
     *
     * @param reqType
     * 			{@link RequestType} 请求类型  GET、 POST 、 DELETE 、 PUT
     * @param url
     * 			{@link String} 请求目标地址
     * @param headers
     * 			{@link Map} 请求头
     * @param param
     * 			{@link Object} 参数
     */
    public static JSONObject sendTokenHttp(RequestType reqType, String url, Map<String, String> headers, Object param)
    		throws Exception{
    	HttpRequestBase reqBase = reqType.getHttpType(url);
    	CloseableHttpClient httpClient = getHttpClient();
    	//设置请求url
    	//config(reqBase);
    	LOGGER.info("token请求头："+headers);
    	LOGGER.info("token请求参数："+param);
    	LOGGER.info("token请求地址："+url);
    	//设置请求头
    	if(MapUtils.isNotEmpty(headers)) {
    		for(Map.Entry<String, String> entry :headers.entrySet()) {
    			reqBase.setHeader(entry.getKey(), entry.getValue());
    		}
    	}
    	
    	//添加参数 参数是json字符串
    	if(param != null && param instanceof String) {
    		String paramStr = String.valueOf(param);
    		((HttpEntityEnclosingRequest) reqBase).setEntity(
					new StringEntity(String.valueOf(paramStr),ContentType.create("application/json", "UTF-8")));
    	}
    	//参数时字节流数组
    	else if(param != null && param instanceof byte[]) {
    		byte[] paramBytes = (byte[])param;
    		((HttpEntityEnclosingRequest) reqBase).setEntity(new ByteArrayEntity(paramBytes));
    	}
    	
    	
    	//响应对象
    	CloseableHttpResponse res = null;
    	//响应内容
    	String resCtx = null;
    	try {
    		//执行请求
    		res = httpClient.execute(reqBase);
    		
    		if(res.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
    			throw new Exception("--->>HTTP访问异常:"+res.getStatusLine());
    		}
    		
    		//获取请求响应对象和响应entity
    		HttpEntity httpEntity = res.getEntity();
    		if(httpEntity != null) {
    			resCtx = EntityUtils.toString(httpEntity,"utf-8");
    		}
    		
		} catch (Exception e) {
			LOGGER.error(e);
			throw new Exception("请求失败",e);
		}finally {
			if(res != null) {
				res.close();
			}
		}
    	LOGGER.info("获取token返回："+resCtx);
    	return JSONObject.parseObject(resCtx);
    }
    
    public static JSONObject sendHttp(RequestType reqType, String url, Map<String, String> headers, Object param)
    		throws Exception{
    	HttpRequestBase reqBase = reqType.getHttpType(url);
    	CloseableHttpClient httpClient = getHttpClient();
    	LOGGER.info("请求头："+headers);
    	LOGGER.info("请求参数："+param);
    	LOGGER.info("请求地址："+url);
    	//设置请求url
    	config(reqBase);
    	
    	//设置请求头
    	if(MapUtils.isNotEmpty(headers)) {
    		for(Map.Entry<String, String> entry :headers.entrySet()) {
    			reqBase.setHeader(entry.getKey(), entry.getValue());
    		}
    	}
    	
    	//添加参数 参数是json字符串
    	if(param != null && param instanceof String) {
    		String paramStr = String.valueOf(param);
    		((HttpEntityEnclosingRequest) reqBase).setEntity(
					new StringEntity(String.valueOf(paramStr),ContentType.create("application/json", "UTF-8")));
    	}
    	//参数时字节流数组
    	else if(param != null && param instanceof byte[]) {
    		byte[] paramBytes = (byte[])param;
    		((HttpEntityEnclosingRequest) reqBase).setEntity(new ByteArrayEntity(paramBytes));
    	}

    	//响应对象
    	CloseableHttpResponse res = null;
    	//响应内容
    	String resCtx = null;
    	try {
    		//执行请求
    		res = httpClient.execute(reqBase);
    		
    		if(res.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
    			throw new Exception("--->>HTTP访问异常:"+res.getStatusLine());
    		}
    		
    		//获取请求响应对象和响应entity
    		HttpEntity httpEntity = res.getEntity();
    		if(httpEntity != null) {
    			resCtx = EntityUtils.toString(httpEntity,"utf-8");
    			LOGGER.info("--->>获取响应内容："+resCtx);
    		}
    		
		} catch (Exception e) {
			LOGGER.error(e);
			throw new Exception("请求失败",e);
		}finally {
			if(res != null) {
				res.close();
			}
		}
    	return JSONObject.parseObject(resCtx);
    }
    
    

    private static Boolean getHeader(HttpMessage message, String name) {
        Header header = message.getFirstHeader(name);
        return header != null;
    }

    private static byte[] decompress(byte[] data) throws IOException {
        ByteArrayInputStream input = new ByteArrayInputStream(data);
        GZIPInputStream gzipInput = new GZIPInputStream(input);
        return IOUtils.toByteArray(gzipInput);
    }
    
	/**
	 * @description 请求头和超时时间配置
	 */
	private static void config(HttpRequestBase httpReqBase) {
	    // 配置请求的超时设置  
	    RequestConfig requestConfig = RequestConfig.custom()  
	                .setConnectionRequestTimeout(MAX_TIMEOUT)  
	                .setConnectTimeout(MAX_TIMEOUT)  
	                .setSocketTimeout(MAX_TIMEOUT)
	                .build();
	    httpReqBase.setConfig(requestConfig);        
	}
	
	/**
	 * @description 连接池配置
	 */
	private static void cfgPoolMgr() {
		ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
    	LayeredConnectionSocketFactory sslsf = SSLConnectionSocketFactory.getSocketFactory();
    	
    	Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
    			.register("http", plainsf)
    			.register("https", sslsf)
    			.build();
    	
    	//连接池管理器
    	connMgr = new PoolingHttpClientConnectionManager(registry);
    	//最大连接数
    	connMgr.setMaxTotal(MAX_TOTAL);
    	//每个路由基础的连接数
    	connMgr.setDefaultMaxPerRoute(ROUTE_MAX_TOTAL);
	}
	
	
	/**
	 * @description 设置重试机制
	 */
	private static void cfgRetryHandler() {
		retryHandler = new HttpRequestRetryHandler() {
			
			@Override
			public boolean retryRequest(IOException e, int excCount, HttpContext ctx) {
				//超过最大重试次数，就放弃
				if(excCount > MAX_RETRY) {
					return false;
				}
				//服务器丢掉了链接，就重试
				if(e instanceof NoHttpResponseException) {
					return true;
				}
				//不重试SSL握手异常
				if(e instanceof SSLHandshakeException) {
					return false;
				}
				//中断
				if(e instanceof InterruptedIOException) {
					return false;
				}
				//目标服务器不可达
				if(e instanceof UnknownHostException) {
					return false;
				}
				//连接超时
				if(e instanceof ConnectTimeoutException) {
					return false;
				}
				//SSL异常
				if(e instanceof SSLException) {
					return false;
				}
				
				HttpClientContext clientCtx = HttpClientContext.adapt(ctx);
				HttpRequest req = clientCtx.getRequest();
				//如果是幂等请求，就再次尝试
				if(!(req instanceof HttpEntityEnclosingRequest)) {
					return true;
				}
				
				return false;
			}
		};
	}
	
	/**
	 * @description 获取HttpClient
	 */
	private static CloseableHttpClient getHttpClient() {
		return HttpClients.custom()
				.setConnectionManager(connMgr)
				.setRetryHandler(retryHandler)
				.disableContentCompression()
				.build();
	}

}
